/**
 * @file STL_TcpServer.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-02-08
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#ifndef __STL_TCP_SERVER_H__
#define __STL_TCP_SERVER_H__

#include <string>
#include <stdint.h>
#include <functional>
#include <thread>
#include <mutex>
#include <list>
#include <queue>
#include <memory>
#include <map>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include "STL_Tools.h"

#define STL_TcpServer_Buffer_Max 32 * 1024

namespace STL
{
    class STL_TcpServer
    {
    public:
        typedef enum Status_e
        {
            None,
            Init,
            Listen,
            Working,
            ERROR,
            Over
        } Status;
        typedef struct TcpServerConfig_t
        {
            std::string ip = "127.0.0.1";
            uint16_t port = 80;
            TcpServerConfig_t(uint16_t port)
            {
                this->port = port;
            }
            TcpServerConfig_t(std::string ip, uint16_t port)
            {
                this->ip = ip;
                this->port = port;
            }
        } TcpServerConfig;
        typedef struct SocketInfo_t
        {
            int socket;
            std::string ip;
            uint16_t port;
            std::mutex mutex;
            std::string data;
            SocketInfo_t(int socket, std::string ip, uint16_t port)
            {
                this->socket = socket;
                this->ip = ip;
                this->port = port;
            }
        } SocketInfo;

        typedef std::function<void(int /* socket*/, std::string /*ip*/, uint16_t /*port*/)> ConnectCallback;
        typedef std::function<void(int /* socket*/)> DisconnectCallback;
        typedef std::function<void(int /* socket*/, std::shared_ptr<std::string>)> DataCallback;

    public:
        STL_TcpServer(TcpServerConfig config);
        ~STL_TcpServer();

    public:
        void sendData(int socket, std::string &data);
        void sendData(int socket, std::string *data)
        {
            sendData(socket, &(*data));
        };
        void closeSocket(int socket);

    public:
        STL_SYNTHESIZE(STL::STL_TcpServer::ConnectCallback, m_ConnectCallback, ConnectCallback);
        STL_SYNTHESIZE(STL::STL_TcpServer::DisconnectCallback, m_DisconnectCallback, DisconnectCallback);
        STL_SYNTHESIZE(STL::STL_TcpServer::DataCallback, m_DataCallback, DataCallback);
        STL_STATUS_CALLBACK(STL_TcpServer::Status);

    public: //operating
        void startListen();
        void stopListen();

    private:                    //event
        int onData(int socket); // -1 连接已断开，0 正常读取数据
        void onConnect(int socket, std::string ip, uint16_t port);
        void onDisconnect(int socket);

    private:
        TcpServerConfig m_config;
        int m_epoll_fd;
        int m_listener_socket;

    private:
        bool m_run;
        std::thread m_thread;
        std::mutex m_mutex;
        void tcpThread();

    private:
        std::map<int /*fd*/, std::shared_ptr<SocketInfo> /*socketinfo*/> m_socketMap;

    private:
        char *m_buffer[STL_TcpServer_Buffer_Max]; //大内存块放到类里,防止频繁开辟空间
    };
} // namespace STL

#endif //__STL_TCP_SERVER_H__